package secret

import (
	"errors"
	"fmt"

	"gitee.com/micro-plat/sas/sas/modules/const/enum"
	"gitee.com/micro-plat/sas/sas/modules/const/models"
	"gitee.com/micro-plat/sas/sas/modules/util"
	per "gitee.com/micro-plat/sas/sas/modules/util/permission"

	"github.com/micro-plat/lib4go/db"
	"github.com/micro-plat/lib4go/errs"
	"github.com/micro-plat/lib4go/types"
)

//GeneralSecret 对象
type GeneralSecret struct {
	db *DBSecret
}

//NewGeneralSecret 创建对象
func NewGeneralSecret() *GeneralSecret {
	return &GeneralSecret{
		db: NewDBSecret(),
	}
}

//Generate 一般密钥生成（md5,sha1,sha256,sha512,hmac,aes,des适用）
func (s *GeneralSecret) Generate(euid, secretType string) (res *Response, err error) {
	sType := enum.GetValueByName(secretType)
	uid, err := s.generateCheck(euid, sType)
	if err != nil {
		return
	}

	//获取随机密钥
	length := 32
	if sType == enum.DES {
		length = 8
	}
	secret := util.GetSecret(length)

	if uid == "" {
		//数据不存在时创建新数据并添加密钥
		uid, err = s.db.addDataAndSecret(euid, secret, sType)
	} else {
		//数据存在时在原数据上添加密钥
		err = s.db.addSecret(uid, secret, sType)
	}
	if err != nil {
		return
	}

	deleteCache(euid)
	return newNormalResponse(uid, secret, "0")
}

func (s *GeneralSecret) generateCheck(euid string, sType int) (uid string, err error) {

	info, err := s.db.GetPermission(euid)
	if err != nil {
		return
	}

	//不存在数据
	if info == nil {
		return
	}

	//密钥已存在
	if info.GetString(enum.GetNameByValue(sType)) != "" {
		err = errs.NewError(enum.ERR_ExistsSecret, fmt.Errorf("要生成的密钥已存在，若要修改该类型密钥请调用set或reset服务"))
		return
	}

	//密钥不存在，获取uid
	uid = info.GetString("uid")
	return
}

//Get 一般密钥获取（md5,sha1,sha256,sha512,hmac,aes,des适用）
func (s *GeneralSecret) Get(euid string, secretType ...string) (res *models.Item, err error) {
	//获取数据
	info, err := GetSecretCache(euid)
	if err != nil {
		return
	}

	//构造返回参数
	return buildResponse(info, secretType...)
}

//Reset 一般密钥重置（md5,sha1,sha256,sha512,hmac,aes,des适用）
func (s *GeneralSecret) Reset(euid, secretType string, item *models.Item) (res *Response, err error) {

	sType := enum.GetValueByName(secretType)
	//获取数据
	info, err := s.existCheck(euid, sType)
	if err != nil {
		return
	}

	//获取密钥并保存
	secret := util.GetSecret(32)
	uid := info.GetString("uid")
	if err := s.db.updateSecret(uid, secret, sType, item.ExpireTime); err != nil {
		return nil, err
	}

	//构造返回参数
	deleteCache(euid)
	status := types.DecodeString(per.Check(info.GetInt("status"), sType), true, "0", "1")
	return newNormalResponse(uid, secret, status)
}

func (s *GeneralSecret) existCheck(euid string, sType int) (info db.QueryRow, err error) {

	info, err = s.db.GetPermission(euid)
	if err != nil {
		return
	}

	//不存在数据
	if info == nil {
		err = errs.NewError(enum.ERR_NotExits, fmt.Errorf("数据不存在"))
		return
	}

	//密钥不存在
	if info.GetString(enum.GetNameByValue(sType)) == "" {
		err = errs.NewError(enum.ERR_NotExitsSecretType, fmt.Errorf("该类型密钥不存在：%d", sType))
		return
	}

	return
}

//Enable 一般密钥启用（md5,sha1,sha256,sha512,hmac,aes,des适用）
func (s *GeneralSecret) Enable(euid, secretType string) (res *Response, err error) {
	sType := enum.GetValueByName(secretType)
	//获取数据
	info, err := s.existCheck(euid, sType)
	if err != nil {
		return
	}

	//一般密钥启用
	uid := info.GetString("uid")
	if !per.Check(info.GetInt("status"), sType) {
		if err := s.db.enableSecret(uid, sType); err != nil {
			return nil, err
		}
	}

	//构造返回参数
	deleteCache(euid)
	secret := info.GetString(enum.GetNameByValue(sType))
	return newResponse(uid, secret, "0")
}

//Disable 一般密钥禁用（md5,sha1,sha256,sha512,hmac,aes,des适用）
func (s *GeneralSecret) Disable(euid, secretType string) (res *Response, err error) {
	sType := enum.GetValueByName(secretType)
	//获取数据
	info, err := s.existCheck(euid, sType)
	if err != nil {
		return
	}

	//一般密钥禁用
	uid := info.GetString("uid")
	if per.Check(info.GetInt("status"), sType) {
		if err := s.db.disableSecret(uid, sType); err != nil {
			return nil, err
		}
	}

	//构造返回参数
	deleteCache(euid)
	secret := info.GetString(enum.GetNameByValue(sType))
	return newResponse(uid, secret, "1")
}

//Set 一般密钥设置（md5,sha1,sha256,sha512,hmac,aes,des适用）
func (s *GeneralSecret) Set(euid, secretType, secret string, expireTime string) (res *Response, err error) {
	if secret == "" {
		err = errors.New("secret:不能设置为空")
		return
	}

	sType := enum.GetValueByName(secretType)
	//获取数据
	info, err := s.existCheck(euid, sType)
	if err != nil {
		return
	}

	//保存密钥
	uid := info.GetString("uid")
	if err := s.db.updateSecret(uid, secret, sType, expireTime); err != nil {
		return nil, err
	}

	//构造返回参数
	deleteCache(euid)
	status := types.DecodeString(per.Check(info.GetInt("status"), sType), true, "0", "1")
	return newNormalResponse(uid, secret, status)
}
